#ifndef __OPCODES_HPP_
#define __OPCODES_HPP_

#include "gc.h"
#include "gc_cpp.h"
#include "gc_allocator.h"

#include "sys/types.h"
#include "rep/rep.hpp"

namespace vm{
  
  enum Opcode{
    NOOP,
    BUILTIN,
    CALL,
    GO_CONT, 
    MAKE_CONT,
    STORE,
    LOAD,
    END
  };
  
  enum RefKind{
    LOCAL, //a->up, b->offset
    INDIRECT, //a->sideways, b->offset
    UP_IND, //a->up, b->sideways, c->offset
    IND_UP, //a->sidways, b->up, c->offset
    UNSIGNED,
    SIGNED, 
    TOPLEVEL //unsigned->offset from top level env.
  };
  
  struct Ref{
    RefKind kind;
    union{
      struct{
        uint8_t a;
        uint8_t b;
        uint8_t c;
        uint8_t d;
      } parts;
      uint32_t un;
      int32_t sig;
    };
    
    /**
     * Find the target of this reference with respect to the given
     * environement.
     */
    rep::Slot* dereference(rep::Slot* env);
    rep::Slot value(rep::Slot* env);
  };
  
  struct Instruction{
  public:
    Instruction(Opcode code, uint8_t argc, Ref a) :
      op(code),
      numpop(argc),
      arg(a)
    {}
    Instruction(){}
    Opcode op;
    uint8_t numpop; //number of things to pop
    Ref arg; //not used for all instructions
  };
  
};

#endif __OPCODES_HPP_
